import uuid

import loguru
from tybase.tools.image_utils import url_to_md5_without_ext
import os
from tybase.tools.video_utils import get_video_resolution
import subprocess
from tybase.tools.video_utils import convert_and_split_video
import sys
import subprocess
import tempfile
sys.path.append("..")  # 也可以这样

from tybase.tools.down_tools import FileDownloader
import config



# 把一个视频按帧分割出来
import subprocess
import loguru
import requests
from urllib.parse import urlparse
import os
import time
import random

downloader = FileDownloader(save_dir="./downloads")

def get_frame_rate(video_path):
    cmd = f'ffprobe -v error -select_streams v:0 -show_entries stream=r_frame_rate -of default=noprint_wrappers=1:nokey=1 {video_path}'
    frame_rate_str = subprocess.getoutput(cmd).strip()
    numerator, denominator = map(int, frame_rate_str.split('/'))
    return numerator / denominator

def convert_and_split_video(video_url: str, target_frame_rate: int, save_path: str, frame_name: str = "frame_%04d.png",
                            qv: int = 5):
    """
    from tybase.tools.video_utils import convert_and_split_video

    convert_and_split_video(
        "https://ty-huanlian.oss-cn-shanghai.aliyuncs.com/videos/20230628/74011b30c0cd50cd4a7dd1fa29a6368f_final.mp4",
        15,
        save_path="/root/autodl-tmp/roopapi/res"
    )
    转换并拆分视频为指定帧率的图片帧和音频文件。

    :param video_url: 视频文件的路径或URL。可以是本地文件路径，也可以是远程URL。
    :param target_frame_rate: 目标帧率。如果视频的当前帧率与目标帧率不同，将会转换视频的帧率。
    :param save_path: 图片帧和音频文件的保存目录。函数会确保该目录存在。
    :param frame_name: 图片帧的命名模式。默认为 "frame_%04d.png"。
    :param qv: 图片帧的质量。默认为 5。 0-31，值越小，图片质量越高。
    :return: 保存目录的路径。包含已拆分的图片帧和音频文件。

    """
    # 确保保存路径存在
    os.makedirs(save_path, exist_ok=True)

    # 获取视频的当前帧率
    current_frame_rate = get_frame_rate(video_url)

    tmp_video_path = None  # 初始化为 None

    # 判断当前帧率是否等于目标帧率
    if current_frame_rate != target_frame_rate:
        print("开始转换帧率,...")
        tmp_video_path = tempfile.mktemp(suffix=".mp4")

        # 使用ffmpeg命令将视频转换到目标帧率
        cmd_convert = f'ffmpeg -thread_queue_size 512 -i {video_url} -r {target_frame_rate} {tmp_video_path}'
        subprocess.call(cmd_convert, shell=True)

        video_url = tmp_video_path  # 更新视频路径为转换后的视频路径

    # 使用ffmpeg命令将视频分割成帧
    # 如果图片是png,采用下面的这个命令,如果是jpg,则采用另外一套命令
    if frame_name.endswith(".png"):
        cmd_split = f'ffmpeg -thread_queue_size 512 -i {video_url} -vf fps={target_frame_rate} {save_path}/{frame_name}'
    else:
        # 用 ffmpeg -i input_video.mp4 -vf "fps=1" -q:v 15 out%d.jpg 这个方式
        cmd_split = f'ffmpeg -thread_queue_size 512 -i {video_url} -vf "fps={target_frame_rate}" -q:v {qv} {save_path}/{frame_name}'
    subprocess.call(cmd_split, shell=True)

    # 使用ffmpeg命令将视频中的音频分离出来
    cmd_audio = f'ffmpeg -thread_queue_size 512 -i {video_url} -vn -acodec copy {save_path}/audio.aac'
    subprocess.call(cmd_audio, shell=True)

    if tmp_video_path and os.path.exists(tmp_video_path):  # 检查文件是否存在
        os.remove(tmp_video_path)  # 删除临时转换后的视频文件
    
    return save_path



def split_video_into_frames(video_url: str, kSourceVideosFrame: str, frames: int = 15, force_update: bool = False,
                            frame_name="frame_%04d.jpg"):
    """
    对用户提供的视频进行拆分并保存到本地。
    :param video_url: 用户提供的视频url
    :param kSourceVideosFrame: 本地保存视频拆分帧的目录
    :param frames: 需要拆分的帧数
    :param force_update: 是否强制更新本地文件
    :param frame_name: 拆分后的帧的名称
    :return: 本地存储的视频帧目录
    """
    # 生成MD5和目标文件夹路径
    md5_without_ext = url_to_md5_without_ext(video_url)
    # 再加一个uuid的命名方式

    # 把线上的路径转换成本地的路径
    video_url_loc = downloader.download_file(video_url)
    
    # 拼接成本地的绝对路径
    video_loc_frame_path = os.path.join(kSourceVideosFrame, f'{md5_without_ext}_{str(uuid.uuid1())}_{frames}')

    # 检查文件是否已经存在(外面有走了删除的逻辑,所以永远也不可能是存在的)
    if os.path.exists(video_loc_frame_path) and not force_update:
        return video_loc_frame_path

    # 如果文件不存在，或者需要强制更新，则开始拆分视频
    os.makedirs(video_loc_frame_path, exist_ok=True)

    # 需要根据帧数进行转换
    loguru.logger.info(f"开始根据帧数来切割视频: {video_url_loc} 到 {video_loc_frame_path}")
    convert_and_split_video(video_url_loc, frames, video_loc_frame_path, frame_name=frame_name,qv=config.qv)

    loguru.logger.debug(f"本地的地址是:-> [{video_url_loc}]")
    os.remove(video_url_loc)
    # 可以删除吗?
    return video_loc_frame_path


# 根据分辨率来添加水印
def 加水印(video_file_path, watermark_text="Generated by AI", position="bottom-right", fontfile_path=None,
           font_size_ratio=70, font_color="white@1"):
    """
    在给定视频文件上添加自定义水印。

    参数:
        video_file_path (str): 需要添加水印的视频文件路径。
        watermark_text (str, 可选): 水印文本，默认为 "Generated by AI"。
        position (str, 可选): 水印位置，支持 "bottom-right" 等，默认在右下角。
        fontfile_path (str, 可选): 字体文件路径，默认为 'LXGWHeartSerifCHS.ttf'。
        font_size_ratio (int, 可选): 字体大小比例，默认为42，字体大小将为视频宽度除以该值。
        font_color (str, 可选): 字体颜色，默认为 "white@1"。

    返回:
        None: 该函数将直接覆盖原始视频文件，添加水印。

    示例:
        加水印('example.mp4', watermark_text='版权所有', position='bottom-right')

    注意:
        确保字体文件路径指向有效的字体文件，否则将无法添加水印。
    """
    # 获取当前脚本的目录
    script_dir = os.path.dirname(os.path.realpath(__file__))
    # 如果未提供字体文件路径，则使用默认字体文件路径
    if fontfile_path is None:
        fontfile_path = os.path.join(script_dir, '..', 'resources', 'LXGWHeartSerifCHS.ttf')

    width, height = get_video_resolution(video_file_path)  # 获取分辨率
    font_size = width // font_size_ratio

    # # 根据位置参数设置坐标
    # x, y = (0, 0)  # 默认坐标
    # if position == "bottom-right":
    #     x, y = f"(main_w-text_w)/2", f"main_h-text_h-0.01*main_h"



    # 根据位置参数设置坐标
    x, y = (0, 0)  # 默认坐标
    if position == "bottom-center":
        x, y = "(w-text_w)/2", "h-text_h-0.02*h"  # 水平居中，垂直位于底部
    elif position == "top-left":
        x, y = "0.01*w", "0.01*h"  # 左上角
    elif position == "top-right":
        x, y = "w-text_w-0.01*w", "0.02*h"  # 右上角
    elif position == "bottom-left":
        x, y = "0.01*w", "h-text_h-0.02*h"  # 左下角
    elif position == "bottom-right":
        x, y = "w-text_w-0.01*w", "h-text_h-0.02*h"  # 右下角
    else:
        x, y = "w-text_w-0.01*w", "h-text_h-0.02*h"  # 右下角

    # 使用subprocess.run来运行ffmpeg命令
    file_name_obj = os.path.basename(video_file_path).split(".")[0]
    output_file_path = f"output_{file_name_obj}.mp4"  # 这里的文件应该也要是绝对路径的!!!
    shell_command = [
        "ffmpeg",
        # "-thread_queue_size", "512",  # 增加线程队列大小
        "-i", video_file_path,
        "-vf",
        f'''drawtext=fontfile={fontfile_path}:text='{watermark_text}':fontsize={font_size}:fontcolor={font_color}:x={x}:y={y}''',
        output_file_path,
        "-y"
    ]

    result = subprocess.run(shell_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    os.rename(output_file_path, video_file_path)  # 从命令
    # 加水印的时候有问题?
    if result.returncode != 0:
        print(f"添加水印时出错: {result.stderr.decode('utf-8')}")
        return
    print(f"{video_file_path} 已加水印.")


# 重写了`synthesize_video`这个方法,加入了音频文件如果不存在就不会合成
def synthesize_video(image_directory, audio_path, output_path, frame_rate, crf=20, frame_name="frame_%04d.png"):
    '''
    from tybase.tools.video_utils import synthesize_video

    :param image_directory: 图片帧的目录
    :param audio_path:  音频文件的路径
    :param output_path:  输出视频的路径
    :param frame_rate: 视频的帧率
    :param crf:  视频的质量,最佳是23,18-20是无损的,数字越小,质量越高,但是文件越大
    :param frame_name: 需要合成的图片帧的命名格式
    :return: 视频合成以后的路径
    '''
    import os
    import subprocess

    # 构建图像文件路径，按照给定的命名格式
    input_images = os.path.join(image_directory, frame_name)

    # 使用 ffmpeg 命令合成视频
    command = ['ffmpeg',
            "-thread_queue_size", "512",  # 增加线程队列大小
            '-framerate', str(frame_rate),  # 设置帧率
            '-i', input_images]  # 输入图片文件路径

    # 检查音频文件是否存在，如果存在，则添加相关的参数
    if os.path.exists(audio_path):
        command.extend(['-i', audio_path])
        command.extend(['-strict', 'experimental'])
        command.extend(['-map', '0', '-map', '1'])  # 明确指定映射顺序，0代表第一个输入（图像），1代表第二个输入（音频）
        
    command.extend(['-c:v', 'libx264',  # 视频编码格式
                    '-pix_fmt', 'yuv420p',  # 设置像素格式
                    '-crf', f'{crf}',  # 设置质量，数字越小质量越高
                    '-y', output_path])  # 输出视频文件路径

    # 执行命令
    subprocess.run(command)
    return output_path



def is_online_video(video_path):
    return urlparse(video_path).scheme in ('http', 'https')

def download_video(video_url):
    response = requests.get(video_url, stream=True)
    if response.status_code == 200:
        # 使用时间戳和随机数创建唯一的文件名
        temp_filename = f"temp_video_{int(time.time())}_{random.randint(0, 999999)}.mp4"
        with open(temp_filename, 'wb') as f:
            for chunk in response.iter_content(chunk_size=1024):
                f.write(chunk)
        return temp_filename
    else:
        raise Exception(f"视频下载失败: 状态码 {response.status_code}")

def extract_frames(video_path, output_folder):
    original_video_path = video_path
    # 检查是否为在线视频
    if is_online_video(video_path):
        loguru.logger.info(f"下载在线视频: {video_path}")
        video_path = download_video(video_path)

    cmd = [
        'ffmpeg', 
        "-thread_queue_size", "512",
        '-i', video_path, 
        '-vf', 'fps=1', 
        f'{output_folder}/output_frame_%d.jpg'
    ]
    subprocess.run(cmd)
    loguru.logger.info(f"视频分割完成: {original_video_path} -> {output_folder}")

    # 删除下载的临时视频文件
    if is_online_video(original_video_path):
        os.remove(video_path)
        loguru.logger.info(f"已删除临时视频文件: {video_path}")